From 5c2c65912200789c3edd9c574d619b65e398ccb2 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 18 Oct 2014 05:45:21 +0200 Subject: [PATCH] stylecontext: Split out functionality into custom object GtkCssNodeDeclaration is a new struct with copy-on-write semantics. It encapsulated the properties used to define a node in the CSS tree. The idea is to use it in various places for caching, in particular as key in hash tables. --- gtk/Makefile.am | 2 + gtk/gtkcssnodedeclaration.c | 528 +++++++++++++++++++++++++++++ gtk/gtkcssnodedeclarationprivate.h | 67 ++++ gtk/gtkstylecontext.c | 357 +++---------------- 4 files changed, 648 insertions(+), 306 deletions(-) create mode 100644 gtk/gtkcssnodedeclaration.c create mode 100644 gtk/gtkcssnodedeclarationprivate.h diff --git a/gtk/Makefile.am b/gtk/Makefile.am index ee3293274a..41943da5cb 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -558,6 +558,7 @@ gtk_private_h_sources = \ gtkcsskeyframesprivate.h \ gtkcsslookupprivate.h \ gtkcssmatcherprivate.h \ + gtkcssnodedeclarationprivate.h \ gtkcssnumbervalueprivate.h \ gtkcssparserprivate.h \ gtkcsspositionvalueprivate.h \ @@ -881,6 +882,7 @@ gtk_base_c_sources = \ gtkcsskeyframes.c \ gtkcsslookup.c \ gtkcssmatcher.c \ + gtkcssnodedeclaration.c \ gtkcssnumbervalue.c \ gtkcssparser.c \ gtkcsspositionvalue.c \ diff --git a/gtk/gtkcssnodedeclaration.c b/gtk/gtkcssnodedeclaration.c new file mode 100644 index 0000000000..b5874ff177 --- /dev/null +++ b/gtk/gtkcssnodedeclaration.c @@ -0,0 +1,528 @@ +/* + * Copyright © 2014 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gtkcssnodedeclarationprivate.h" + +#include + +typedef struct _GtkRegion GtkRegion; + +struct _GtkRegion +{ + GQuark class_quark; + GtkRegionFlags flags; +}; + +struct _GtkCssNodeDeclaration { + guint refcount; + GtkJunctionSides junction_sides; + GtkStateFlags state; + guint n_classes; + guint n_regions; + /* GQuark classes[n_classes]; */ + /* GtkRegion region[n_regions]; */ +}; + +static inline GQuark * +get_classes (const GtkCssNodeDeclaration *decl) +{ + return (GQuark *) (decl + 1); +} + +static inline GtkRegion * +get_regions (const GtkCssNodeDeclaration *decl) +{ + return (GtkRegion *) (get_classes (decl) + decl->n_classes); +} + +static inline gsize +sizeof_node (guint n_classes, + guint n_regions) +{ + return sizeof (GtkCssNodeDeclaration) + + sizeof (GQuark) * n_classes + + sizeof (GtkRegion) * n_regions; +} + +static inline gsize +sizeof_this_node (GtkCssNodeDeclaration *decl) +{ + return sizeof_node (decl->n_classes, decl->n_regions); +} + +static void +gtk_css_node_declaration_make_writable (GtkCssNodeDeclaration **decl) +{ + if ((*decl)->refcount == 1) + return; + + (*decl)->refcount--; + + *decl = g_memdup (*decl, sizeof_this_node (*decl)); + (*decl)->refcount = 1; +} + +static void +gtk_css_node_declaration_make_writable_resize (GtkCssNodeDeclaration **decl, + gsize offset, + gsize bytes_added, + gsize bytes_removed) +{ + gsize old_size = sizeof_this_node (*decl); + gsize new_size = old_size + bytes_added - bytes_removed; + + if ((*decl)->refcount == 1) + { + if (bytes_removed > 0 && old_size - offset - bytes_removed > 0) + memmove (((char *) *decl) + offset + bytes_removed, ((char *) *decl) + offset, old_size - offset - bytes_removed); + *decl = g_realloc (*decl, new_size); + if (bytes_added > 0 && old_size - offset > 0) + memmove (((char *) *decl) + offset + bytes_added, ((char *) *decl) + offset, old_size - offset); + } + else + { + GtkCssNodeDeclaration *old = *decl; + + old->refcount--; + + *decl = g_malloc (new_size); + memcpy (*decl, old, offset); + if (old_size - offset - bytes_removed > 0) + memcpy (((char *) *decl) + offset + bytes_added, ((char *) old) + offset + bytes_removed, old_size - offset - bytes_removed); + (*decl)->refcount = 1; + } +} + +GtkCssNodeDeclaration * +gtk_css_node_declaration_new (void) +{ + static GtkCssNodeDeclaration empty = { + 1, /* need to own a ref ourselves so the copy-on-write path kicks in when people change things */ + 0, + 0, + 0, + 0 + }; + + return gtk_css_node_declaration_ref (&empty); +} + +GtkCssNodeDeclaration * +gtk_css_node_declaration_ref (GtkCssNodeDeclaration *decl) +{ + decl->refcount++; + + return decl; +} + +void +gtk_css_node_declaration_unref (GtkCssNodeDeclaration *decl) +{ + decl->refcount--; + if (decl->refcount > 0) + return; + + g_free (decl); +} + +gboolean +gtk_css_node_declaration_set_junction_sides (GtkCssNodeDeclaration **decl, + GtkJunctionSides junction_sides) +{ + if ((*decl)->junction_sides == junction_sides) + return FALSE; + + gtk_css_node_declaration_make_writable (decl); + (*decl)->junction_sides = junction_sides; + + return TRUE; +} + +GtkJunctionSides +gtk_css_node_declaration_get_junction_sides (const GtkCssNodeDeclaration *decl) +{ + return decl->junction_sides; +} + +gboolean +gtk_css_node_declaration_set_state (GtkCssNodeDeclaration **decl, + GtkStateFlags state) +{ + if ((*decl)->state == state) + return FALSE; + + gtk_css_node_declaration_make_writable (decl); + (*decl)->state = state; + + return TRUE; +} + +GtkStateFlags +gtk_css_node_declaration_get_state (const GtkCssNodeDeclaration *decl) +{ + return decl->state; +} + +static gboolean +find_class (const GtkCssNodeDeclaration *decl, + GQuark class_quark, + guint *position) +{ + gint min, max, mid; + gboolean found = FALSE; + GQuark *classes; + guint pos; + + if (position) + *position = 0; + + if (decl->n_classes == 0) + return FALSE; + + min = 0; + max = decl->n_classes - 1; + classes = get_classes (decl); + + do + { + GQuark item; + + mid = (min + max) / 2; + item = classes[mid]; + + if (class_quark == item) + { + found = TRUE; + pos = mid; + break; + } + else if (class_quark > item) + min = pos = mid + 1; + else + { + max = mid - 1; + pos = mid; + } + } + while (min <= max); + + if (position) + *position = pos; + + return found; +} + +gboolean +gtk_css_node_declaration_add_class (GtkCssNodeDeclaration **decl, + GQuark class_quark) +{ + guint pos; + + if (find_class (*decl, class_quark, &pos)) + return FALSE; + + gtk_css_node_declaration_make_writable_resize (decl, + (char *) &get_classes (*decl)[pos] - (char *) *decl, + sizeof (GQuark), + 0); + (*decl)->n_classes++; + get_classes(*decl)[pos] = class_quark; + + return TRUE; +} + +gboolean +gtk_css_node_declaration_remove_class (GtkCssNodeDeclaration **decl, + GQuark class_quark) +{ + guint pos; + + if (!find_class (*decl, class_quark, &pos)) + return FALSE; + + gtk_css_node_declaration_make_writable_resize (decl, + (char *) &get_classes (*decl)[pos] - (char *) *decl, + 0, + sizeof (GQuark)); + (*decl)->n_classes--; + + return TRUE; +} + +gboolean +gtk_css_node_declaration_has_class (const GtkCssNodeDeclaration *decl, + GQuark class_quark) +{ + return find_class (decl, class_quark, NULL); +} + +GList * +gtk_css_node_declaration_list_classes (const GtkCssNodeDeclaration *decl) +{ + GQuark *classes; + GList *result; + guint i; + + classes = get_classes (decl); + result = NULL; + + for (i = 0; i < decl->n_classes; i++) + { + result = g_list_prepend (result, GUINT_TO_POINTER (classes[i])); + } + + return result; +} + +static gboolean +find_region (const GtkCssNodeDeclaration *decl, + GQuark region_quark, + guint *position) +{ + gint min, max, mid; + gboolean found = FALSE; + GtkRegion *regions; + guint pos; + + if (position) + *position = 0; + + if (decl->n_regions == 0) + return FALSE; + + min = 0; + max = decl->n_regions - 1; + regions = get_regions (decl); + + do + { + GQuark item; + + mid = (min + max) / 2; + item = regions[mid].class_quark; + + if (region_quark == item) + { + found = TRUE; + pos = mid; + break; + } + else if (region_quark > item) + min = pos = mid + 1; + else + { + max = mid - 1; + pos = mid; + } + } + while (min <= max); + + if (position) + *position = pos; + + return found; +} + +gboolean +gtk_css_node_declaration_add_region (GtkCssNodeDeclaration **decl, + GQuark region_quark, + GtkRegionFlags flags) +{ + GtkRegion *regions; + guint pos; + + if (find_region (*decl, region_quark, &pos)) + return FALSE; + + gtk_css_node_declaration_make_writable_resize (decl, + (char *) &get_regions (*decl)[pos] - (char *) *decl, + sizeof (GtkRegion), + 0); + (*decl)->n_regions++; + regions = get_regions(*decl); + regions[pos].class_quark = region_quark; + regions[pos].flags = flags; + + return TRUE; +} + +gboolean +gtk_css_node_declaration_remove_region (GtkCssNodeDeclaration **decl, + GQuark region_quark) +{ + guint pos; + + if (!find_region (*decl, region_quark, &pos)) + return FALSE; + + gtk_css_node_declaration_make_writable_resize (decl, + (char *) &get_regions (*decl)[pos] - (char *) *decl, + 0, + sizeof (GtkRegion)); + (*decl)->n_regions--; + + return TRUE; +} + +gboolean +gtk_css_node_declaration_has_region (const GtkCssNodeDeclaration *decl, + GQuark region_quark, + GtkRegionFlags *flags_return) +{ + guint pos; + + if (!find_region (decl, region_quark, &pos)) + { + if (flags_return) + *flags_return = 0; + return FALSE; + } + + if (flags_return) + *flags_return = get_regions (decl)[pos].flags; + + return TRUE; +} + +GList * +gtk_css_node_declaration_list_regions (const GtkCssNodeDeclaration *decl) +{ + GtkRegion *regions; + GList *result; + guint i; + + regions = get_regions (decl); + result = NULL; + + for (i = 0; i < decl->n_regions; i++) + { + result = g_list_prepend (result, GUINT_TO_POINTER (regions[i].class_quark)); + } + + return result; +} + +guint +gtk_css_node_declaration_hash (gconstpointer elem) +{ + const GtkCssNodeDeclaration *decl = elem; + GQuark *classes; + GtkRegion *regions; + guint hash, i; + + hash = 0; + + classes = get_classes (decl); + for (i = 0; i < decl->n_classes; i++) + { + hash <<= 5; + hash += classes[i]; + } + + regions = get_regions (decl); + for (i = 0; i < decl->n_regions; i++) + { + hash <<= 5; + hash += regions[i].class_quark; + hash += regions[i].flags; + } + + hash ^= ((guint) decl->junction_sides) << (sizeof (guint) * 8 - 5); + hash ^= decl->state; + + return hash; +} + +gboolean +gtk_css_node_declaration_equal (gconstpointer elem1, + gconstpointer elem2) +{ + const GtkCssNodeDeclaration *decl1 = elem1; + const GtkCssNodeDeclaration *decl2 = elem2; + GQuark *classes1, *classes2; + GtkRegion *regions1, *regions2; + guint i; + + if (decl1 == decl2) + return TRUE; + + if (decl1->state != decl2->state) + return FALSE; + + if (decl1->n_classes != decl2->n_classes) + return FALSE; + + classes1 = get_classes (decl1); + classes2 = get_classes (decl2); + for (i = 0; i < decl1->n_classes; i++) + { + if (classes1[i] != classes2[i]) + return FALSE; + } + + if (decl1->n_regions != decl2->n_regions) + return FALSE; + + regions1 = get_regions (decl1); + regions2 = get_regions (decl2); + for (i = 0; i < decl1->n_regions; i++) + { + if (regions1[i].class_quark != regions2[i].class_quark || + regions1[i].flags != regions2[i].flags) + return FALSE; + } + + if (decl1->junction_sides != decl2->junction_sides) + return FALSE; + + return TRUE; +} + +void +gtk_css_node_declaration_add_to_widget_path (const GtkCssNodeDeclaration *decl, + GtkWidgetPath *path, + guint pos) +{ + GQuark *classes; + GtkRegion *regions; + guint i; + + /* Set widget regions */ + regions = get_regions (decl); + for (i = 0; i < decl->n_regions; i++) + { +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_widget_path_iter_add_region (path, pos, + g_quark_to_string (regions[i].class_quark), + regions[i].flags); +G_GNUC_END_IGNORE_DEPRECATIONS + } + + /* Set widget classes */ + classes = get_classes (decl); + for (i = 0; i < decl->n_classes; i++) + { + gtk_widget_path_iter_add_class (path, pos, + g_quark_to_string (classes[i])); + } + + /* Set widget state */ + gtk_widget_path_iter_set_state (path, pos, decl->state); +} + diff --git a/gtk/gtkcssnodedeclarationprivate.h b/gtk/gtkcssnodedeclarationprivate.h new file mode 100644 index 0000000000..767b6ecfb5 --- /dev/null +++ b/gtk/gtkcssnodedeclarationprivate.h @@ -0,0 +1,67 @@ +/* + * Copyright © 2014 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef __GTK_CSS_NODE_DECLARATION_PRIVATE_H__ +#define __GTK_CSS_NODE_DECLARATION_PRIVATE_H__ + +#include "gtkenums.h" +#include "gtkwidgetpath.h" + +G_BEGIN_DECLS + +typedef struct _GtkCssNodeDeclaration GtkCssNodeDeclaration; + + +GtkCssNodeDeclaration * gtk_css_node_declaration_new (void); +GtkCssNodeDeclaration * gtk_css_node_declaration_ref (GtkCssNodeDeclaration *decl); +void gtk_css_node_declaration_unref (GtkCssNodeDeclaration *decl); + +gboolean gtk_css_node_declaration_set_junction_sides (GtkCssNodeDeclaration **decl, + GtkJunctionSides junction_sides); +GtkJunctionSides gtk_css_node_declaration_get_junction_sides (const GtkCssNodeDeclaration *decl); +gboolean gtk_css_node_declaration_set_state (GtkCssNodeDeclaration **decl, + GtkStateFlags flags); +GtkStateFlags gtk_css_node_declaration_get_state (const GtkCssNodeDeclaration *decl); + +gboolean gtk_css_node_declaration_add_class (GtkCssNodeDeclaration **decl, + GQuark class_quark); +gboolean gtk_css_node_declaration_remove_class (GtkCssNodeDeclaration **decl, + GQuark class_quark); +gboolean gtk_css_node_declaration_has_class (const GtkCssNodeDeclaration *decl, + GQuark class_quark); +GList * gtk_css_node_declaration_list_classes (const GtkCssNodeDeclaration *decl); + +gboolean gtk_css_node_declaration_add_region (GtkCssNodeDeclaration **decl, + GQuark region_quark, + GtkRegionFlags flags); +gboolean gtk_css_node_declaration_remove_region (GtkCssNodeDeclaration **decl, + GQuark region_quark); +gboolean gtk_css_node_declaration_has_region (const GtkCssNodeDeclaration *decl, + GQuark region_quark, + GtkRegionFlags *flags_return); +GList * gtk_css_node_declaration_list_regions (const GtkCssNodeDeclaration *decl); + +guint gtk_css_node_declaration_hash (gconstpointer elem); +gboolean gtk_css_node_declaration_equal (gconstpointer elem1, + gconstpointer elem2); + +void gtk_css_node_declaration_add_to_widget_path (const GtkCssNodeDeclaration *decl, + GtkWidgetPath *path, + guint pos); +G_END_DECLS + +#endif /* __GTK_CSS_NODE_DECLARATION_PRIVATE_H__ */ diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index 97785f326e..8ef33af127 100644 --- a/gtk/gtkstylecontext.c +++ b/gtk/gtkstylecontext.c @@ -28,6 +28,7 @@ #include "gtkcsscornervalueprivate.h" #include "gtkcssenumvalueprivate.h" #include "gtkcssimagevalueprivate.h" +#include "gtkcssnodedeclarationprivate.h" #include "gtkcssnumbervalueprivate.h" #include "gtkcssrgbavalueprivate.h" #include "gtkcssshadowsvalueprivate.h" @@ -129,15 +130,8 @@ #define GTK_STYLE_CONTEXT_CACHED_CHANGE (GTK_CSS_CHANGE_STATE) typedef struct GtkStyleInfo GtkStyleInfo; -typedef struct GtkRegion GtkRegion; typedef struct PropertyValue PropertyValue; -struct GtkRegion -{ - GQuark class_quark; - GtkRegionFlags flags; -}; - struct PropertyValue { GType widget_type; @@ -147,10 +141,7 @@ struct PropertyValue struct GtkStyleInfo { - GArray *style_classes; - GArray *regions; - GtkJunctionSides junction_sides; - GtkStateFlags state_flags; + GtkCssNodeDeclaration *decl; GtkCssComputedValues *values; }; @@ -306,8 +297,7 @@ style_info_new (void) GtkStyleInfo *info; info = g_slice_new0 (GtkStyleInfo); - info->style_classes = g_array_new (FALSE, FALSE, sizeof (GQuark)); - info->regions = g_array_new (FALSE, FALSE, sizeof (GtkRegion)); + info->decl = gtk_css_node_declaration_new (); return info; } @@ -333,8 +323,7 @@ style_info_free (GtkStyleInfo *info) { if (info->values) g_object_unref (info->values); - g_array_free (info->style_classes, TRUE); - g_array_free (info->regions, TRUE); + gtk_css_node_declaration_unref (info->decl); g_slice_free (GtkStyleInfo, info); } @@ -356,16 +345,7 @@ style_info_copy (GtkStyleInfo *info) GtkStyleInfo *copy; copy = style_info_new (); - g_array_insert_vals (copy->style_classes, 0, - info->style_classes->data, - info->style_classes->len); - - g_array_insert_vals (copy->regions, 0, - info->regions->data, - info->regions->len); - - copy->junction_sides = info->junction_sides; - copy->state_flags = info->state_flags; + copy->decl = gtk_css_node_declaration_ref (info->decl); style_info_set_values (copy, info->values); return copy; @@ -374,28 +354,9 @@ style_info_copy (GtkStyleInfo *info) static guint style_info_hash (gconstpointer elem) { - const GtkStyleInfo *info; - guint i, hash = 0; - - info = elem; - - for (i = 0; i < info->style_classes->len; i++) - { - hash += g_array_index (info->style_classes, GQuark, i); - hash <<= 5; - } + const GtkStyleInfo *info = elem; - for (i = 0; i < info->regions->len; i++) - { - GtkRegion *region; - - region = &g_array_index (info->regions, GtkRegion, i); - hash += region->class_quark; - hash += region->flags; - hash <<= 5; - } - - return hash ^ info->state_flags; + return gtk_css_node_declaration_hash (info->decl); } static gboolean @@ -407,29 +368,7 @@ style_info_equal (gconstpointer elem1, info1 = elem1; info2 = elem2; - if (info1->state_flags != info2->state_flags) - return FALSE; - - if (info1->junction_sides != info2->junction_sides) - return FALSE; - - if (info1->style_classes->len != info2->style_classes->len) - return FALSE; - - if (memcmp (info1->style_classes->data, - info2->style_classes->data, - info1->style_classes->len * sizeof (GQuark)) != 0) - return FALSE; - - if (info1->regions->len != info2->regions->len) - return FALSE; - - if (memcmp (info1->regions->data, - info2->regions->data, - info1->regions->len * sizeof (GtkRegion)) != 0) - return FALSE; - - return TRUE; + return gtk_css_node_declaration_equal (info1->decl, info2->decl); } static void @@ -490,7 +429,7 @@ gtk_style_context_init (GtkStyleContext *style_context) /* Create default info store */ priv->info = style_info_new (); - priv->info->state_flags = GTK_STATE_FLAG_DIR_LTR; + gtk_css_node_declaration_set_state (&priv->info->decl, GTK_STATE_FLAG_DIR_LTR); priv->property_cache = g_array_new (FALSE, FALSE, sizeof (PropertyValue)); @@ -717,40 +656,6 @@ gtk_style_context_is_saved (GtkStyleContext *context) return context->priv->saved_nodes != NULL; } -static void -style_info_add_to_widget_path (GtkStyleInfo *info, - GtkWidgetPath *path, - guint pos) -{ - guint i; - - /* Set widget regions */ - for (i = 0; i < info->regions->len; i++) - { - GtkRegion *region; - - region = &g_array_index (info->regions, GtkRegion, i); -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - gtk_widget_path_iter_add_region (path, pos, - g_quark_to_string (region->class_quark), - region->flags); -G_GNUC_END_IGNORE_DEPRECATIONS - } - - /* Set widget classes */ - for (i = 0; i < info->style_classes->len; i++) - { - GQuark quark; - - quark = g_array_index (info->style_classes, GQuark, i); - gtk_widget_path_iter_add_class (path, pos, - g_quark_to_string (quark)); - } - - /* Set widget state */ - gtk_widget_path_iter_set_state (path, pos, info->state_flags); -} - static GtkWidgetPath * create_query_path (GtkStyleContext *context, GtkStyleInfo *info) @@ -767,15 +672,15 @@ create_query_path (GtkStyleContext *context, GtkStyleInfo *root = g_slist_last (context->priv->saved_nodes)->data; if (length > 0) - style_info_add_to_widget_path (root, path, length - 1); + gtk_css_node_declaration_add_to_widget_path (root->decl, path, length - 1); - gtk_widget_path_append_type (path, length > 0 ?gtk_widget_path_iter_get_object_type (path, length - 1) : G_TYPE_NONE); - style_info_add_to_widget_path (info, path, length); + gtk_widget_path_append_type (path, length > 0 ? gtk_widget_path_iter_get_object_type (path, length - 1) : G_TYPE_NONE); + gtk_css_node_declaration_add_to_widget_path (info->decl, path, length); } else { if (length > 0) - style_info_add_to_widget_path (info, path, length - 1); + gtk_css_node_declaration_add_to_widget_path (info->decl, path, length - 1); } return path; @@ -856,7 +761,7 @@ style_values_lookup_for_state (GtkStyleContext *context, { GtkCssComputedValues *values; - if (context->priv->info->state_flags == state) + if (gtk_css_node_declaration_get_state (context->priv->info->decl) == state) return style_values_lookup (context); gtk_style_context_save (context); @@ -1296,11 +1201,10 @@ gtk_style_context_set_state (GtkStyleContext *context, GtkStateFlags old_flags; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - old_flags = context->priv->info->state_flags; - if (old_flags == flags) - return; + old_flags = gtk_css_node_declaration_get_state (context->priv->info->decl); - context->priv->info->state_flags = flags; + if (!gtk_css_node_declaration_set_state (&context->priv->info->decl, flags)) + return; if (((old_flags ^ flags) & (GTK_STATE_FLAG_DIR_LTR | GTK_STATE_FLAG_DIR_RTL)) && !gtk_style_context_is_saved (context)) @@ -1324,7 +1228,7 @@ gtk_style_context_get_state (GtkStyleContext *context) { g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0); - return context->priv->info->state_flags; + return gtk_css_node_declaration_get_state (context->priv->info->decl); } /** @@ -1583,98 +1487,6 @@ gtk_style_context_restore (GtkStyleContext *context) gtk_style_context_pop_style_info (context); } -static gboolean -style_class_find (GArray *array, - GQuark class_quark, - guint *position) -{ - gint min, max, mid; - gboolean found = FALSE; - guint pos; - - if (position) - *position = 0; - - if (!array || array->len == 0) - return FALSE; - - min = 0; - max = array->len - 1; - - do - { - GQuark item; - - mid = (min + max) / 2; - item = g_array_index (array, GQuark, mid); - - if (class_quark == item) - { - found = TRUE; - pos = mid; - } - else if (class_quark > item) - min = pos = mid + 1; - else - { - max = mid - 1; - pos = mid; - } - } - while (!found && min <= max); - - if (position) - *position = pos; - - return found; -} - -static gboolean -region_find (GArray *array, - GQuark class_quark, - guint *position) -{ - gint min, max, mid; - gboolean found = FALSE; - guint pos; - - if (position) - *position = 0; - - if (!array || array->len == 0) - return FALSE; - - min = 0; - max = array->len - 1; - - do - { - GtkRegion *region; - - mid = (min + max) / 2; - region = &g_array_index (array, GtkRegion, mid); - - if (region->class_quark == class_quark) - { - found = TRUE; - pos = mid; - } - else if (region->class_quark > class_quark) - min = pos = mid + 1; - else - { - max = mid - 1; - pos = mid; - } - } - while (!found && min <= max); - - if (position) - *position = pos; - - return found; -} - /** * gtk_style_context_add_class: * @context: a #GtkStyleContext @@ -1704,9 +1516,7 @@ gtk_style_context_add_class (GtkStyleContext *context, const gchar *class_name) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; GQuark class_quark; - guint position; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (class_name != NULL); @@ -1714,14 +1524,8 @@ gtk_style_context_add_class (GtkStyleContext *context, priv = context->priv; class_quark = g_quark_from_string (class_name); - info = priv->info; - - if (!style_class_find (info->style_classes, class_quark, &position)) - { - g_array_insert_val (info->style_classes, position, class_quark); - - gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS); - } + if (gtk_css_node_declaration_add_class (&priv->info->decl, class_quark)) + gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS); } /** @@ -1738,9 +1542,7 @@ gtk_style_context_remove_class (GtkStyleContext *context, const gchar *class_name) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; GQuark class_quark; - guint position; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (class_name != NULL); @@ -1752,14 +1554,8 @@ gtk_style_context_remove_class (GtkStyleContext *context, priv = context->priv; - info = priv->info; - - if (style_class_find (info->style_classes, class_quark, &position)) - { - g_array_remove_index (info->style_classes, position); - - gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS); - } + if (gtk_css_node_declaration_remove_class (&priv->info->decl, class_quark)) + gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_CLASS); } /** @@ -1779,7 +1575,6 @@ gtk_style_context_has_class (GtkStyleContext *context, const gchar *class_name) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; GQuark class_quark; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); @@ -1792,12 +1587,18 @@ gtk_style_context_has_class (GtkStyleContext *context, priv = context->priv; - info = priv->info; + return gtk_css_node_declaration_has_class (priv->info->decl, class_quark); +} - if (style_class_find (info->style_classes, class_quark, NULL)) - return TRUE; +static void +quarks_to_strings (GList *list) +{ + GList *l; - return FALSE; + for (l = list; l; l = l->next) + { + l->data = (char *) g_quark_to_string (GPOINTER_TO_UINT (l->data)); + } } /** @@ -1817,23 +1618,14 @@ GList * gtk_style_context_list_classes (GtkStyleContext *context) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; - GList *classes = NULL; - guint i; + GList *classes; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); priv = context->priv; - - info = priv->info; - - for (i = 0; i < info->style_classes->len; i++) - { - GQuark quark; - - quark = g_array_index (info->style_classes, GQuark, i); - classes = g_list_prepend (classes, (gchar *) g_quark_to_string (quark)); - } + + classes = gtk_css_node_declaration_list_classes (priv->info->decl); + quarks_to_strings (classes); return classes; } @@ -1857,28 +1649,16 @@ GList * gtk_style_context_list_regions (GtkStyleContext *context) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; - GList *classes = NULL; - guint i; + GList *regions; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL); priv = context->priv; - info = priv->info; - - for (i = 0; i < info->regions->len; i++) - { - GtkRegion *region; - const gchar *class_name; - - region = &g_array_index (info->regions, GtkRegion, i); + regions = gtk_css_node_declaration_list_regions (priv->info->decl); + quarks_to_strings (regions); - class_name = g_quark_to_string (region->class_quark); - classes = g_list_prepend (classes, (gchar *) class_name); - } - - return classes; + return regions; } gboolean @@ -1940,9 +1720,7 @@ gtk_style_context_add_region (GtkStyleContext *context, GtkRegionFlags flags) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; GQuark region_quark; - guint position; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (region_name != NULL); @@ -1951,19 +1729,8 @@ gtk_style_context_add_region (GtkStyleContext *context, priv = context->priv; region_quark = g_quark_from_string (region_name); - info = priv->info; - - if (!region_find (info->regions, region_quark, &position)) - { - GtkRegion region; - - region.class_quark = region_quark; - region.flags = flags; - - g_array_insert_val (info->regions, position, region); - - gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION); - } + if (gtk_css_node_declaration_add_region (&priv->info->decl, region_quark, flags)) + gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION); } /** @@ -1982,9 +1749,7 @@ gtk_style_context_remove_region (GtkStyleContext *context, const gchar *region_name) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; GQuark region_quark; - guint position; g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); g_return_if_fail (region_name != NULL); @@ -1996,14 +1761,8 @@ gtk_style_context_remove_region (GtkStyleContext *context, priv = context->priv; - info = priv->info; - - if (region_find (info->regions, region_quark, &position)) - { - g_array_remove_index (info->regions, position); - - gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION); - } + if (gtk_css_node_declaration_remove_region (&priv->info->decl, region_quark)) + gtk_style_context_queue_invalidate_internal (context, GTK_CSS_CHANGE_REGION); } /** @@ -2028,9 +1787,7 @@ gtk_style_context_has_region (GtkStyleContext *context, GtkRegionFlags *flags_return) { GtkStyleContextPrivate *priv; - GtkStyleInfo *info; GQuark region_quark; - guint position; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE); g_return_val_if_fail (region_name != NULL, FALSE); @@ -2045,21 +1802,7 @@ gtk_style_context_has_region (GtkStyleContext *context, priv = context->priv; - info = priv->info; - - if (region_find (info->regions, region_quark, &position)) - { - if (flags_return) - { - GtkRegion *region; - - region = &g_array_index (info->regions, GtkRegion, position); - *flags_return = region->flags; - } - return TRUE; - } - - return FALSE; + return gtk_css_node_declaration_has_region (priv->info->decl, region_quark, flags_return); } static gint @@ -2629,7 +2372,7 @@ gtk_style_context_set_junction_sides (GtkStyleContext *context, { g_return_if_fail (GTK_IS_STYLE_CONTEXT (context)); - context->priv->info->junction_sides = sides; + gtk_css_node_declaration_set_junction_sides (&context->priv->info->decl, sides); } /** @@ -2647,7 +2390,7 @@ gtk_style_context_get_junction_sides (GtkStyleContext *context) { g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0); - return context->priv->info->junction_sides; + return gtk_css_node_declaration_get_junction_sides (context->priv->info->decl); } gboolean @@ -3854,6 +3597,7 @@ _gtk_style_context_get_icon_lookup_flags (GtkStyleContext *context) { GtkCssIconStyle icon_style; GtkIconLookupFlags flags; + GtkStateFlags state; g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), 0); @@ -3875,9 +3619,10 @@ _gtk_style_context_get_icon_lookup_flags (GtkStyleContext *context) return 0; } - if (context->priv->info->state_flags & GTK_STATE_FLAG_DIR_LTR) + state = gtk_style_context_get_state (context); + if (state & GTK_STATE_FLAG_DIR_LTR) flags |= GTK_ICON_LOOKUP_DIR_LTR; - else if (context->priv->info->state_flags & GTK_STATE_FLAG_DIR_RTL) + else if (state & GTK_STATE_FLAG_DIR_RTL) flags |= GTK_ICON_LOOKUP_DIR_RTL; return flags; -- 2.30.2